home *** CD-ROM | disk | FTP | other *** search
-
- /*
- * scanf.c
- *
- * Copyright (c) 1991 Symantec Corporation. All rights reserved.
- *
- */
-
- #include "stdio.h"
- #include "stdarg.h"
- #include "limits.h"
- #include "ctype.h"
- #include "errno.h"
- #include "ansi_private.h"
- #include <SANE.h>
-
- static void clearset(int);
- static void invertset(void);
- static void setbit(int);
- static int testbit(int);
-
- #define TRUE 1
- #define FALSE 0
-
- static struct format {
- unsigned suppress : 1;
- unsigned haveWidth : 1;
- unsigned fetchBase : 1;
- unsigned negate : 1;
- unsigned valid : 1;
- unsigned unsigned_ : 1;
- unsigned floating : 1;
- unsigned dot : 1;
- unsigned hSize : 1;
- unsigned lSize : 1;
- unsigned LSize : 1;
- int fieldWidth;
- } default_format;
-
- struct decrec {
- char sgn;
- short exp;
- char sig[SIGDIGLEN];
- };
-
- static void dtof(short, struct decrec *, void *);
-
- static char scanset[32];
-
-
- int
- _vfscanf(FILE *fp, const char *fmt, va_list arg)
- {
- int nassigned = 0, nconverted = 0, nread = 0;
- int overflow, state;
- unsigned char first;
- register short c, base, digit;
- register long result;
- register char *s;
- struct format F;
- struct decrec D;
-
- for (c = *fmt; c; c = *++fmt) {
- if (c != '%')
- goto match1;
- F = default_format;
-
- /* check for assignment-suppression flag */
-
- c = *++fmt;
- if (c == '*') {
- F.suppress = TRUE;
- c = *++fmt;
- }
-
- /* decode field width */
-
- if (isdigit(c)) {
- F.haveWidth = TRUE;
- do {
- F.fieldWidth = (10 * F.fieldWidth) + (c - '0');
- c = *++fmt;
- } while (isdigit(c));
- if (F.fieldWidth <= 0)
- goto done;
- }
-
- /* determine appropriate conversion */
-
- conv: switch (c) {
-
- /* 'h' size modifier */
-
- case 'h':
- F.hSize = TRUE;
- c = *++fmt;
- goto conv;
-
- /* 'l' size modifier */
-
- case 'l':
- F.lSize = TRUE;
- c = *++fmt;
- goto conv;
-
- /* 'L' size modifier */
-
- case 'L':
- F.LSize = TRUE;
- c = *++fmt;
- goto conv;
-
- /* '?' base modifier */
-
- case '?':
- F.fetchBase = TRUE;
- c = *++fmt;
- goto conv;
-
- /* decimal (signed) */
-
- case 'd':
- base = 10;
- goto conv_signed;
-
- /* integer (signed) */
-
- case 'i':
- base = 0;
- goto conv_signed;
-
- /* octal (unsigned) */
-
- case 'o':
- base = 8;
- goto conv_unsigned;
-
- /* decimal (unsigned) */
-
- case 'u':
- base = 10;
- goto conv_unsigned;
-
- /* hexadecimal (unsigned) */
-
- case 'p':
- F.lSize = TRUE;
- /* ... */
- case 'x':
- case 'X':
- base = 16;
- goto conv_unsigned;
-
- #ifndef _NOFLOATING_
- /* floating point */
-
- case 'e':
- case 'E':
- case 'f':
- case 'g':
- case 'G':
- F.floating = TRUE;
- state = -1;
- goto scan;
- #endif _NOFLOATING_
-
- /* string */
-
- case 's':
- do {
- c = getc(fp), ++nread;
- } while (isspace(c));
- clearset(1);
- goto string;
-
- /* scanset */
-
- case '[':
- c = *++fmt;
- if (c == '^') {
- F.negate = TRUE;
- c = *++fmt;
- }
- clearset(0);
- for (;;) {
- if (c == '\0')
- goto done;
- setbit((unsigned char) c);
- c = *++fmt;
- if (c == ']')
- break;
- if (c == '-' && fmt[1] != ']' && fmt[1] >= (first = fmt[-1])) {
- for (c = *++fmt; first != c; setbit(first++))
- ;
- }
- }
- if (F.negate)
- invertset();
- c = getc(fp), ++nread;
- goto string;
-
- /* character */
-
- case 'c':
- if (!F.haveWidth)
- F.fieldWidth = 1;
- if (!F.suppress)
- s = va_arg(arg, char *);
- while (F.fieldWidth-- > 0) {
- if ((c = getc(fp)) == EOF)
- goto done;
- if (!F.suppress)
- *s++ = c;
- ++nread;
- }
- if (!F.suppress)
- ++nassigned;
- ++nconverted;
- continue;
-
- /* store # bytes read so far */
-
- case 'n':
- result = nread;
- if (!F.suppress)
- --nassigned;
- goto assign;
-
- /* others */
-
- default:
- if (c != '%')
- goto done;
- match1:
- if (isspace(c)) {
- do {
- c = getc(fp), ++nread;
- } while (isspace(c));
- ungetc(c, fp), --nread;
- }
- else {
- if ((c = getc(fp)) != (unsigned char) *fmt) {
- ungetc(c, fp);
- goto done;
- }
- ++nread;
- }
- continue;
- }
- /*NOTREACHED*/
-
- /* string scanner */
-
- string:
- if (!F.haveWidth)
- F.fieldWidth = INT_MAX;
- if (!F.suppress)
- s = va_arg(arg, char *);
- for (; c != EOF; c = getc(fp), ++nread) {
- --F.fieldWidth;
- if (!testbit(c))
- break;
- F.valid = TRUE;
- if (!F.suppress)
- *s++ = c;
- if (F.fieldWidth == 0)
- goto endstring;
- }
- ungetc(c, fp), --nread;
- endstring:
- if (!F.valid)
- goto done;
- if (!F.suppress) {
- *s = 0;
- ++nassigned;
- }
- ++nconverted;
- continue;
-
- /* integer conversions */
-
- conv_unsigned:
- F.unsigned_ = TRUE;
- conv_signed:
- if (F.fetchBase)
- base = va_arg(arg, int);
- state = 0;
-
- /* numeric scanner */
-
- scan: result = 0;
- do {
- c = getc(fp), ++nread;
- } while (isspace(c));
- if (!F.haveWidth)
- F.fieldWidth = INT_MAX;
- overflow = FALSE;
- for (; c != EOF; c = getc(fp), ++nread) {
- --F.fieldWidth;
- switch (state) {
-
- /* (integer) start state */
-
- case 0:
- state = 1;
- if (c == '-') {
- F.negate = TRUE;
- break;
- }
- if (c == '+')
- break;
- /* ... */
-
- /* (integer) look for leading '0' */
-
- case 1:
- state = 3;
- if (c == '0') {
- F.valid = TRUE;
- if (F.fieldWidth) {
- if (base == 0) {
- base = 8;
- state = 2;
- }
- else if (base == 16)
- state = 2;
- }
- break;
- }
- goto state3;
-
- /* (integer) look for leading '0x' */
-
- case 2:
- state = 3;
- if (c == 'x' || c == 'X') {
- base = 16;
- F.valid = FALSE;
- break;
- }
- /* ... */
-
- /* (integer) process each digit */
-
- case 3:
- state3:
- digit = c;
- if (digit >= '0' && digit <= '9')
- digit -= '0';
- else if (digit >= 'A' && digit <= 'Z')
- digit -= 'A' - 10;
- else if (digit >= 'a' && digit <= 'z')
- digit -= 'a' - 10;
- else
- goto pushback;
- if (base == 0)
- base = 10;
- if (digit >= base)
- goto pushback;
- asm {
- move.l result,d0
- swap d0
- mulu base,d0
- swap d0
- tst.w d0
- bne.s @1
- move.w digit,d0
- mulu base,result
- add.l d0,result
- bcc.s @2
- @1 st overflow
- @2 }
- F.valid = TRUE;
- break;
-
- #ifndef _NOFLOATING_
- /* (floating) start state */
-
- case -1:
- state = -2;
- D.exp = 0;
- D.sig[0] = 0;
- if (c == '-') {
- D.sgn = 1;
- break;
- }
- D.sgn = 0;
- if (c == '+')
- break;
- /* ... */
-
- /* (floating) process each digit */
-
- case -2:
- if (c >= '0' && c <= '9') {
- F.valid = TRUE;
- if (c != '0' || D.sig[0]) {
- if (D.sig[0] >= sizeof D.sig - 1) {
- if (!F.dot)
- ++D.exp;
- break;
- }
- D.sig[++D.sig[0]] = c;
- }
- if (F.dot)
- --D.exp;
- }
- else if (c == '.' && !F.dot)
- F.dot = TRUE;
- else if ((c == 'e' || c == 'E') && F.valid) {
- base = 10;
- F.valid = FALSE;
- state = 0;
- }
- else
- goto pushback;
- break;
- #endif _NOFLOATING_
- }
-
- /* get next character */
-
- if (F.fieldWidth == 0)
- goto endscan;
- }
-
- /* push back last character read */
-
- pushback:
- ungetc(c, fp), --nread;
- endscan:
- if (!F.valid)
- goto done;
-
- /* set sign of result */
-
- if (F.negate && result) {
- result = -result;
- if (F.unsigned_ || result > 0)
- overflow = TRUE;
- }
- else if (!F.unsigned_ && result < 0)
- overflow = TRUE;
-
- /* see if result fits */
-
- #ifndef _NOFLOATING_
- if (F.floating) asm {
- movea.w D.exp,a0
- add.l a0,result
- bvs.s @3
- movea.l result,a0
- cmpa.w a0,a0
- beq.s @4
- @3 st overflow
- @4 }
- else
- #endif _NOFLOATING_
- if (F.hSize) {
- if (F.unsigned_) {
- if ((unsigned short) result != result)
- overflow = TRUE;
- }
- else {
- if ((short) result != result)
- overflow = TRUE;
- }
- }
- else if (!F.lSize) {
- if (F.unsigned_) {
- if ((unsigned int) result != result)
- overflow = TRUE;
- }
- else {
- if ((int) result != result)
- overflow = TRUE;
- }
- }
-
- /* report overflow */
-
- if (overflow) {
- if (F.unsigned_)
- result = 0;
- else if (F.hSize || F.floating)
- result = SHRT_MIN;
- else if (F.lSize)
- result = LONG_MIN;
- else
- result = INT_MIN;
- if (!F.negate)
- result = ~result;
- if (!F.floating)
- errno = ERANGE;
- }
-
- /* assign result */
-
- assign:
- if (!F.suppress) {
- s = va_arg(arg, void *);
- #ifndef _NOFLOATING_
- if (F.floating) {
- D.exp = result;
- if (F.lSize) {
- #if __option(double_8)
- F.hSize = TRUE;
- #else
- F.LSize = TRUE;
- #endif
- }
- if (F.LSize)
- dtof(FFEXT, &D, s);
- else if (F.hSize)
- dtof(FFDBL, &D, s);
- else
- dtof(FFSGL, &D, s);
- }
- else
- #endif _NOFLOATING_
- if (F.lSize)
- * (long *) s = result;
- else if (F.hSize)
- * (short *) s = result;
- else
- * (int *) s = result;
- ++nassigned;
- }
- ++nconverted;
- }
-
- /* all done! */
-
- done:
- if (nconverted == 0 && c == EOF)
- return(EOF);
- return(nassigned);
- }
-
-
- /* ---------- scanset primitives ---------- */
-
-
- /*
- * clearset - initialize set to "nothing" or "everything but whitespace"
- *
- */
-
- static void
- clearset(int whitespace)
- {
- asm {
- lea scanset,a0
- moveq #0,d0
- move.l d0,(a0)+
- move.l d0,(a0)+
- move.l d0,(a0)+
- move.l d0,(a0)+
- move.l d0,(a0)+
- move.l d0,(a0)+
- move.l d0,(a0)+
- move.l d0,(a0)+
- }
- if (whitespace) {
- scanset[1] = 0x3E; /* \t \n \v \f \r */
- scanset[4] = 0x01; /* space */
- invertset();
- }
- }
-
-
- /*
- * setbit - add character to scan set
- *
- */
-
- static void
- setbit(int c)
- {
- scanset[c >> 3] |= (1 << (c & 7));
- }
-
-
- /*
- * invertset - complement scan set
- *
- */
-
- static void
- invertset(void)
- {
- asm {
- lea scanset,a0
- not.l (a0)+
- not.l (a0)+
- not.l (a0)+
- not.l (a0)+
- not.l (a0)+
- not.l (a0)+
- not.l (a0)+
- not.l (a0)+
- }
- }
-
-
- /*
- * testbit - see if character is in scanset
- *
- */
-
- static int
- testbit(int c)
- {
- return(scanset[c >> 3] & (1 << (c & 7)));
- }
-
-
- /* ---------- floating-point conversion ---------- */
-
-
- #ifndef _NOFLOATING_
- static void
- dtof(short code, struct decrec *d, void *p)
- {
- short excp, kind, c = '0';
- #if __option(mc68881) || !__option(native_fp)
- register short *q = p;
-
- if (code == FFEXT)
- p = q + 1;
- #endif
- fp68k(&excp, (short) FPROCENTRY);
- if (d->sig[0]) {
- fp68k(d, p, (short) (FOD2B + code));
- fp68k(&excp, (short) FGETENV);
- fp68k(p, &kind, (short) (FOCLASS + code));
- if (kind < 0)
- kind = -kind;
- if (kind == FCINF || (excp & (OVERFLOW<<8)))
- c = 'I';
- else if (kind == FCNORM && !(excp & (UNDERFLOW<<8)))
- goto done;
- errno = ERANGE;
- }
-
- /* result is zero or infinity */
-
- if (c == '0')
- d->sgn = 0;
- d->exp = 0;
- d->sig[0] = 1;
- d->sig[1] = c;
- fp68k(d, p, (short) (FOD2B + code));
-
- /* done */
-
- done:
- #if __option(mc68881) || !__option(native_fp)
- if (code == FFEXT) {
- q[0] = q[1];
- #if __option(native_fp)
- q[1] = 0;
- #endif
- }
- #endif
- return;
- }
- #endif _NOFLOATING_
-